/**
 *******************************************************************************************************************************************
 * @file        posix_fsm.c
 * @brief       有限状态机实现
 * @details     /
 * @since       Change Logs:
 * Date         Author       Notes
 * 2022-12-08   lzh          the first version
 * @remark      使用方法 :
 *
 * 1.依据用户需求, 建立 fsm_event_handle 表, 枚举事件/状态;
 *
 * 2.创建 fsm_t 对象, 并将 fsm_event_handle 与之绑定;
 *
 * 3.根据用户程序需求设定不同 event 以调用 fsm_event_exec() 执行对应动作;
 *
 * 约定 <当前状态 + 一个事件> 只能有一个 动作回调 ,一般会设置一个事件为特权级事件(常用于挂起)
 *******************************************************************************************************************************************
 * @attention
 *
 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH CODING INFORMATION
 * REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A RESULT, SYNWIT SHALL NOT BE HELD LIABLE
 * FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
 * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONN-
 * -ECTION WITH THEIR PRODUCTS.
 *
 * @copyright   2012 Synwit Technology
 *******************************************************************************************************************************************
 */
#include "posix_fsm.h"

/**
 * @brief       获取当前状态
 * @param [in]  fsm   : 状态机句柄
 * @param [in]  state : 当前状态
 * @retval      详见 fsm_result 枚举
 */
fsm_result fsm_state_get(fsm_t *fsm, int *state)
{
    if (pthread_mutex_lock(&fsm->mutex) != 0)
        return FSM_VIE_LOCK;

    *state = fsm->state;
    pthread_mutex_unlock(&fsm->mutex);
    return FSM_RT_OK;
}

/**
 * @brief       切换当前状态
 * @param [in]  fsm   : 状态机句柄
 * @param [in]  state : 期望状态
 * @retval      详见 fsm_result 枚举
 */
fsm_result fsm_state_set(fsm_t *fsm, int state)
{
    if (pthread_mutex_lock(&fsm->mutex) != 0)
        return FSM_VIE_LOCK;

    fsm->state = state;
    pthread_mutex_unlock(&fsm->mutex);
    return FSM_RT_OK;
}

/**
 * @brief       通过该方法获取在当前状态下, 指定事件到来时的对应动作处理回调
 * @param [in]  fsm          : 状态机句柄
 * @param [in]  event        : 触发事件
 * @param [in]  fsm_event_cb : 动作执行回调
 * @retval      详见 fsm_result 枚举
 */
fsm_result fsm_event_handler_get(fsm_t *fsm, int event, fsm_event_cb *action)
{
    unsigned int i = 0;
    *action = NULL;

    if (pthread_mutex_lock(&fsm->mutex) != 0)
        return FSM_VIE_LOCK;

    for (i = 0; i < fsm->table_num; ++i)
    {
        if (fsm->state == fsm->table[i].cur_state && event == fsm->table[i].trigger_event)
        {
            *action = fsm->table[i].do_action;
            break;
        }
    }
    pthread_mutex_unlock(&fsm->mutex);
    return (i < fsm->table_num) ? FSM_RT_OK : FSM_GO_TRAP;
}

/**
 * @brief       当指定事件触发时, 状态机会自动寻找并调用对应的动作处理回调, 从而完成状态转移
 * @param [in]  fsm   : 状态机句柄
 * @param [in]  event : 触发事件
 * @param [in]  data  : 事件参数
 * @retval      详见 fsm_result 枚举
 */
fsm_result fsm_event_exec(fsm_t *fsm, int event, void *data)
{
    unsigned int i = 0;

    if (pthread_mutex_lock(&fsm->mutex) != 0)
        return FSM_VIE_LOCK;

    for (i = 0; i < fsm->table_num; ++i)
    {
        if (fsm->state == fsm->table[i].cur_state && event == fsm->table[i].trigger_event)
        {
            int transfer_state = fsm->table[i].next_state;
            if (fsm->table[i].do_action != NULL)
            {
                transfer_state = fsm->table[i].do_action(data); /* 动作执行 */
            }
            //printf("change state [%d] -> [%d]\n", fsm->state, fsm->table[i].next_state);
            fsm->state = transfer_state;
            break;
        }
    }
    pthread_mutex_unlock(&fsm->mutex);
    return (i < fsm->table_num) ? FSM_RT_OK : FSM_GO_TRAP;
}
